package de.preamp.clients.java.playlist;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;

import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionEvent;

import de.preamp.clients.java.data.Track;

/**
 * A class representing a playlist. It can be used as an {@link ArrayList} but
 * provides some extra functions. It has an index pointing to the active
 * {@link Track} in this playlist. Some of the methods of {@link ArrayList} are
 * redefined to notifiy {@link ListDataListener} if invoked.
 * <p>
 * This playlist implementation should be used only as dummy. It is created
 * empty at startup and can be filled to test the programm but provides no
 * persistence or database connection functions.
 * 
 * @author André Stannek
 * @version 2010-01-16
 */
public class PlaylistInMemoryImpl extends ArrayList<Track> implements Playlist,
	Serializable
{

    /**
     * Generated UID.
     */
    private static final long serialVersionUID = 5873289716147690652L;

    /**
     * The index of the {@link Track} currently active in this playlist.
     */
    private transient int currentIndex;

    /**
     * The {@link ListDataListener} listening an this playlist.
     */
    private transient Set<ListDataListener> listener;

    /**
     * the name of this playlist.
     */
    private String name;

    /**
     * Standard constructor, constructing an empty playlist.
     * 
     * @param name
     *            the name of the playlist
     */
    public PlaylistInMemoryImpl(final String name)
    {
	super();
	this.name = name;
	listener = new HashSet<ListDataListener>();
	currentIndex = 0;
    }

    /**
     * Constructor creating a new playlist with the content from another
     * playlist.
     * 
     * @param playlist
     *            the playlist with the tracks to add to this playlist
     */
    public PlaylistInMemoryImpl(final Playlist playlist)
    {
	this(playlist.getName());
	for (Track track : playlist)
	{
	    this.add(track);
	}
    }

    @Override
    public final Track getNextTrack()
    {
	if (currentIndex < size() - 1)
	{
	    currentIndex++;
	}
	else
	{
	    currentIndex = 0;
	}
	return get(currentIndex);
    }

    @Override
    public final Track getCurrentTrack()
    {
	return get(currentIndex);
    }

    @Override
    public final Track getPreviousTrack()
    {
	if (currentIndex > 0)
	{
	    currentIndex--;
	}
	else
	{
	    currentIndex = 0;
	}
	return get(currentIndex);
    }

    @Override
    public final boolean add(final Track track)
    {
	final boolean result = super.add(track);
	for (ListDataListener l : listener)
	{
	    l.intervalAdded(new ListDataEvent(this,
		    ListDataEvent.INTERVAL_ADDED, size() - 1, size() - 1));
	}
	return result;
    }

    @Override
    public final void add(final int index, final Track track)
    {
	if (index > size() - 1)
	{
	    super.add(track);
	}
	else
	{
	    super.add(index, track);
	}
	for (ListDataListener l : listener)
	{
	    l.intervalAdded(new ListDataEvent(this,
		    ListDataEvent.INTERVAL_ADDED, index, index));
	}
    }

    @Override
    public final void remove(final Track track)
    {
	final int index = indexOf(track);
	remove(index);
	for (ListDataListener l : listener)
	{
	    l.intervalRemoved(new ListDataEvent(this,
		    ListDataEvent.INTERVAL_REMOVED, index, index));
	}
    }

    @Override
    public final void setIndex(final int index)
    {
	if (index < 0)
	{
	    currentIndex = 0;
	}
	else if (index < size())
	{
	    currentIndex = index;
	}
	else
	{
	    currentIndex = size() - 1;
	}
    }

    @Override
    public final void valueChanged(final ListSelectionEvent event)
    {
	currentIndex = event.getFirstIndex();
    }

    @Override
    public final void addListDataListener(final ListDataListener listener)
    {
	this.listener.add(listener);
    }

    @Override
    public final Object getElementAt(final int index)
    {
	return get(index);
    }

    @Override
    public final int getSize()
    {
	return size();
    }

    @Override
    public final void removeListDataListener(final ListDataListener listener)
    {
	this.listener.remove(listener);
    }

    @Override
    public final String getName()
    {
	return name;
    }

    @Override
    public final void setName(final String name)
    {
	this.name = name;
    }

    /**
     * This method should be called after desiralization of an object.
     */
    public final void postDeserialize()
    {
	listener = new HashSet<ListDataListener>();
    }
}
